﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;

namespace UniRlv.Utility.AppLib
{
    public class NetInDevice : AbtInDevice
    {
        private Socket skt;
        private string ipString;
        private int port;
        private bool bClose;//是否停止
        private bool bPause;
        private byte[] recBuff;
        private Thread td;
        private int recBuffLen = 4096;
        private bool bSocketErr;//是否socket错误导致关闭
        private ManualResetEvent manualResetEvent;   // 线程控制事件， 当被手动Reset()则WaitOne()会使线程阻塞
                                                       // 当被Set()便再不会被阻塞直到Reset()
 
        public NetInDevice()
        {
            InitString = "127.0.0.1,8001";
            Prefix = 0;
            Suffix = "\r\n";

            recBuff = new byte[recBuffLen];
            prcBuff = new List<byte>();

            dataQueue = new Queue<string>();
            manualResetEvent = new ManualResetEvent(true);

            bClose = true;//默认未打开
        }

        public void OnTdExec(object o)
        {
            NetInDevice dev = o as NetInDevice;
            int receivedBytesCount;

            while (!bClose)
            {
                manualResetEvent.WaitOne();  // 用以阻塞线程, 当Set()被调用后恢复，Reset()被调用后阻塞

                try
                {
                    //使用数据缓冲  
                    if (bSocketErr)
                    {//重新连接
                        try
                        {
                            IPAddress ip = IPAddress.Parse(ipString);
                            Console.WriteLine("reconnect!");
                            skt.Connect(ip, port);
                            Console.WriteLine("reconnect ok:{0}!", InitString);
                            bSocketErr = false;
                        }
                        catch (System.Exception ex)
                        {
                            Thread.Sleep(1000);
                            continue;
                        }
                    }

                    receivedBytesCount = skt.Receive(recBuff, recBuffLen, SocketFlags.None);

                    if (bPause)
                    {//暂停，忽略数据
                        receivedBytesCount = 0;
                        continue;
                    }

                    if (receivedBytesCount == 0 && !bClose)
                    {
                        //socket连接已断开  
                        bSocketErr = true;
                        skt.Close();
                        skt = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        continue;
                    }

                    for (int i = 0; i < receivedBytesCount; i++)
                    {
                        prcBuff.Add(dev.recBuff[i]);
                    }

                    while (ByteProccess())
                    {
                        Console.WriteLine("event thread id={0}", Thread.CurrentThread.ManagedThreadId);
                        SetEvent(null);
                    }
 
                }
                catch (SocketException e)
                {
                    //10035 == WSAEWOULDBLOCK  
                    if (e.NativeErrorCode.Equals(10035))
                    {
                        //仍然处于连接状态,但是发送可能被阻塞  
                    }
                    else
                    {
                        //连接错误,返回错误代码:e.NativeErrorCode  
                        bSocketErr = true;
                        skt.Close();
                        skt = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        continue;
                    }
                } 
            }
        }

        public override bool Open()
        {
            if (IsOpen())
            {
                return true;
            } 
            else
            {
                try
                {
                    skt = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                    IPAddress ip = IPAddress.Parse(this.ipString);

	                skt.Connect(ip, port);
                    bClose = false;
                    bPause = false;
                    bSocketErr = false;

                    td = new Thread(OnTdExec);
                    td.IsBackground = true;
	                td.Start(this);

                    return true;
                }
                catch (System.Exception ex)
                {
                    ErrorString = ex.Message;
                    return false;
                }
            }
        }

        public override bool IsOpen()
        {
            return !bClose;
        }

        public override void Close()
        {
            bClose = true;
            manualResetEvent.Set();
            skt.Shutdown(SocketShutdown.Both);
        }

        public override void Pause()
        {
            bPause = true;
        }

        public override void Resume()
        {
            bPause = false;
            prcBuff.Clear();
            dataQueue.Clear();
        }

        public override void SendData(byte[] bytes, int len)
        {
            try
            {
                skt.Send(bytes, len, SocketFlags.None);
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message);
            }
            
        }

        public override string InitString
        {
            get
            {
                return _initString;
            }
            set
            {
                string[] paramStrings = value.Split(',');

                if (paramStrings.Length > 1)
                {
                    ipString = paramStrings[0];
                    port = Convert.ToInt32(paramStrings[1]);

                    _initString = value;
                }
            }
        }
    }
}
